<template>
    <ElForm ref="formRef" :inline="inline" :model="model" :label-width="labelWidth" :rules="rules">
        <ElFormItem v-valid="formCode" v-for="(item, key) in opts" :key="key" :label="item.title" :prop="key">
            <ElInput v-if="item.tag === 'input'" :style="{ width: item.width }" v-model="model[key]" :min="item.min"
                :max="item.max" :placeholder="item.ph" :maxlength="item.max" :type="item.type" :disabled="item.dis" />
            <ElSelect :style="{ width: item.width }" v-else-if="item.tag === 'select'" v-model="model[key]"
                :placeholder="item.ph" :disabled="item.dis">
                <ElOption v-for="child in item.values" :key="child.value" :label="child.label" :value="child.value">
                </ElOption>
            </ElSelect>
            <ElRadioGroup :style="{ width: item.width }" v-else-if="item.tag === 'radio'" v-model="model[key]">
                <ElRadio v-for="child in item.values" :key="child.value" size="large" :label="child.value">{{ child.label }}
                </ElRadio>
            </ElRadioGroup>
            <ElInputNumber :style="{ width: item.width }" v-else-if="item.tag === 'number'" v-model="model[key]">
            </ElInputNumber>
            <ElCascader v-else-if="item.tag === 'cascader'" v-model="model[key]" :style="{ width: item.width }"
                :options="item.values" />
            <ElDatePicker v-else-if="item.tag === 'date'" v-model="model[key]" :style="{ width: item.width }"
                :type="item.type"></ElDatePicker>
        </ElFormItem>
        <ElFormItem v-if="submit || reset || add">
            <ElButton v-valid="formCode" :loading="loading" type="primary" v-if="submit" @click="() => success()">{{ submit
            }}</ElButton>
            <ElButton v-valid="formCode" type="default" v-if="reset" @click="() => formRef.resetFields()">{{ reset }}
            </ElButton>
            <ElButton type="success" v-if="add" v-valid="addCode" @click="$emit('add')">{{ add }}</ElButton>
        </ElFormItem>
        <ElFormItem v-if="$slots.append">
            <slot name="append"></slot>
        </ElFormItem>
    </ElForm>
</template>
<script lang="ts">
export default {
    name: 'Form'
}
</script>
<script lang="ts" setup>
import { computed, ref } from 'vue';

/**
 * 是否为数字
 * @param value 
 */
const isNumber = (value: any) => typeof value === 'number';

/**
 * form表单引用
 */
const formRef = ref();

const props = defineProps({
    model: {
        type: Object,
        required: true
    },
    /**
     * 表单配置项
     */
    options: {
        type: Object,
        required: true
    },
    inline: Boolean,
    labelWidth: {
        type: String,
        default: '65px'
    },
    /**
     * 提交按钮标题
     */
    submit: String,
    /**
     * 重置按钮标题
     */
    reset: String,
    /**
     * 表单区权限编码
     */
    formCode: String,
    /**
     * 添加按钮标题
     */
    add: String,
    /**
     * 添加按钮权限编码
     */
    addCode: String,
    /**
     * 提交loading
     */
    loading: Boolean
});

const emit = defineEmits(['success', 'add']);

/**
 * 规则
 */
const rules = computed(() => {
    const _rules = {} as any;

    for (const key in props.options) {
        if (Object.prototype.hasOwnProperty.call(props.options, key)) {
            //@ts-ignore
            const element = props.options[key];
            const { title, rules } = element;
            _rules[key] = rules || [];
            if (element.required) {
                _rules[key].unshift({ required: true });
            }
            for (const rule of _rules[key]) {
                if (rule.message) continue;
                const { max, min } = rule;
                if (rule.required) {
                    rule.message = `${title}不能为空`;
                }
                else if (isNumber(rule.max) && isNumber(rule.min)) {
                    rule.message = `${title}的长度为${min}至${max}位`;
                }
                else if (isNumber(rule.max)) {
                    rule.message = `${title}的最大长度为${max}`;
                }
                else if (isNumber(rule.min)) {
                    rule.message = `${title}的最小长度为${min}`;
                }
            }
        }
    }

    return _rules;
});

/**
 * 表单配置项
 */
const opts = computed(() => {
    const _options = { ...props.options };
    for (const key in _options) {
        if (Object.prototype.hasOwnProperty.call(_options, key)) {
            //@ts-ignore
            const element = _options[key];
            const { title } = element;
            element.tag = element.tag || 'input';
            element.ph = element.ph?.replace('{t}', title);
        }
    }
    return _options;
});

/**
 * 提交
 */
const success = async () => {
    try {
        await formRef.value?.validate();
        emit('success', props.model);
    } catch (error) { }
}

/**
 * 校验
 */
const valid = async () => {
    try {
        const result = await formRef.value.validate();
        if (result) {
            return props.model;
        }
        return Promise.reject();
    } catch (error) {
        return Promise.reject();
    }
}

defineExpose({
    success,
    valid
});
</script>

<style lang="scss"></style>